<!--
<template>
  <div class="upload-audio">
    <h2>🎙 上传会议音频并自动识别</h2>

    &lt;!&ndash; 文件上传 &ndash;&gt;
    <input type="file" accept="audio/*" @change="onFileChange" />

    &lt;!&ndash; 上传进度条 &ndash;&gt;
    <div v-if="uploading" class="progress">
      <p>上传进度：{{ progress }}%</p>
      <el-progress :percentage="progress"></el-progress>
    </div>

    &lt;!&ndash; 识别状态 &ndash;&gt;
    <div v-if="recognizing" class="recognizing">
      <p>⏳ 语音识别中，请稍候...</p>
      <el-progress :percentage="pollProgress"></el-progress>
    </div>

    &lt;!&ndash; 上传按钮 &ndash;&gt;
    <el-button
        type="primary"
        @click="startUpload"
        :disabled="!file || uploading || recognizing"
    >
      开始上传
    </el-button>

    &lt;!&ndash; 识别结果 &ndash;&gt;
    <div v-if="resultText" class="result">
      <h3>📝 识别结果：</h3>
      <pre>{{ resultText }}</pre>
    </div>

    &lt;!&ndash; 自动摘要 &ndash;&gt;
    <div v-if="summaryText" class="summary">
      <h3>📄 自动生成会议摘要：</h3>
      <pre>{{ summaryText }}</pre>

      &lt;!&ndash; ✅ 导出按钮 &ndash;&gt;
      <div class="export-buttons">
        <el-button type="primary" @click="exportFile('word')">
          导出 Word
        </el-button>
        <el-button type="success" @click="exportFile('pdf')">
          导出 PDF
        </el-button>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref } from "vue";
import axios from "axios";

// ======= 响应式数据 =======
const file = ref(null);
const progress = ref(0);
const uploading = ref(false);
const recognizing = ref(false);
const pollProgress = ref(0);
const resultText = ref("");
const summaryText = ref("");

const CHUNK_SIZE = 5 * 1024 * 1024; // 每块5MB

// ======= 文件选择 =======
function onFileChange(e) {
  const selected = e.target.files[0];
  if (selected) file.value = selected;
}

// ======= 上传文件分片 =======
async function startUpload() {
  uploading.value = true;
  progress.value = 0;
  const totalChunks = Math.ceil(file.value.size / CHUNK_SIZE);
  const fileId = Date.now() + "_" + file.value.name;

  for (let i = 0; i < totalChunks; i++) {
    const chunk = file.value.slice(i * CHUNK_SIZE, Math.min(file.value.size, (i + 1) * CHUNK_SIZE));
    const form = new FormData();
    form.append("file", chunk);
    form.append("fileId", fileId);
    form.append("index", i);

    await axios.post("/api/upload/chunk", form, {
      onUploadProgress: (e) => {
        progress.value = Math.round(((i + e.loaded / e.total) / totalChunks) * 100);
      },
    });
  }

  // 合并分片
  const mergeRes = await axios.post("/api/upload/merge", { fileId, filename: file.value.name });
  uploading.value = false;
  progress.value = 100;

  const filePath = mergeRes.data.url;
  console.log("上传完成：", filePath);

  // ======= 自动调用百度ASR识别 =======
  recognizing.value = true;
  const { data } = await axios.post("/api/asr/baidu", { filePath });
  const taskId = data.taskId;
  await pollRecognition(taskId);
}

// ======= 轮询识别任务 =======
async function pollRecognition(taskId) {
  for (let i = 0; i < 60; i++) { // 最多5分钟
    await new Promise((r) => setTimeout(r, 5000));
    const { data } = await axios.get("/api/asr/status", { params: { taskId } });

    if (data.status === 1) {
      pollProgress.value = Math.min(pollProgress.value + 2, 90);
    } else if (data.status === 2) {
      pollProgress.value = 100;
      resultText.value = data.result || "（未识别出内容）";
      recognizing.value = false;

      // ======= 自动生成摘要 =======
      const summaryRes = await axios.post("/api/summary", { text: resultText.value });
      summaryText.value = summaryRes.data.summary;
      return;
    } else if (data.status === 3) {
      recognizing.value = false;
      alert("识别任务失败！");
      return;
    }
  }
  recognizing.value = false;
  alert("识别超时！");
}

// ======= 导出会议纪要 =======
async function exportFile(type) {
  const endpoint = `/api/export/${type}`;
  const res = await axios.post(
      endpoint,
      {
        title: "AI 智能笔记助手会议纪要",
        summary: summaryText.value,
        text: resultText.value,
      },
      { responseType: "blob" }
  );

  // 下载文件
  const blob = new Blob([res.data]);
  const url = window.URL.createObjectURL(blob);
  const link = document.createElement("a");
  link.href = url;
  link.download = `会议纪要_${Date.now()}.${type === "pdf" ? "pdf" : "docx"}`;
  link.click();
  window.URL.revokeObjectURL(url);
}
</script>

<style scoped>
.upload-audio {
  padding: 20px;
  max-width: 700px;
  margin: auto;
}

.progress,
.recognizing {
  margin-top: 10px;
}

.result,
.summary {
  margin-top: 20px;
  background: #fafafa;
  border-radius: 8px;
  padding: 10px;
}

.export-buttons {
  margin-top: 10px;
  display: flex;
  gap: 10px;
  justify-content: flex-end;
}
</style>
-->

<template>
  <div class="upload-audio">
    <h2>🎙 上传会议音频并自动识别</h2>

    <!-- 文件上传 -->
    <input type="file" accept="audio/*" @change="onFileChange" />

    <!-- 上传按钮 -->
    <el-button
        type="primary"
        @click="startUpload"
        :disabled="!file || uploading || recognizing"
    >
      开始上传
    </el-button>

    <!-- 上传进度条 -->
    <div v-if="uploading" class="progress">
      <p>上传进度：{{ progress }}%</p>
      <el-progress :percentage="progress"></el-progress>
    </div>

    <!-- 识别状态 -->
    <div v-if="recognizing" class="recognizing">
      <p>⏳ 语音识别中，请稍候... (已等待 {{ pollProgress }}%)</p>
      <el-progress :percentage="pollProgress" :status="pollProgress < 100 ? null : 'success'"></el-progress>
    </div>

    <!-- 识别结果 -->
    <div v-if="resultText" class="result">
      <h3>📝 识别结果：</h3>
      <pre>{{ resultText }}</pre>
    </div>

    <!-- 自动摘要 -->
    <div v-if="summaryText" class="summary">
      <h3>📄 自动生成会议摘要：</h3>
      <pre>{{ summaryText }}</pre>

      <!-- ✅ 导出按钮 -->
      <div class="export-buttons">
        <el-button type="primary" @click="exportFile('word')">
          导出 Word
        </el-button>
        <el-button type="success" @click="exportFile('pdf')">
          导出 PDF
        </el-button>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref } from "vue";
//import axios from "axios";
import api from "@/utils/api";

// ======= 响应式数据 =======
const file = ref(null);
const progress = ref(0);
const uploading = ref(false);
const recognizing = ref(false);
// 轮询进度条用于展示等待时长，不是实际的识别进度
const pollProgress = ref(0);
const resultText = ref("");
const summaryText = ref("");

const CHUNK_SIZE = 5 * 1024 * 1024; // 每块5MB
const MAX_POLL_TIME_SECONDS = 300; // 最长等待 5 分钟

// ======= 文件选择 =======
function onFileChange(e) {
  const selected = e.target.files[0];
  if (selected) {
    file.value = selected;
    // 重置结果
    resultText.value = "";
    summaryText.value = "";
    progress.value = 0;
    pollProgress.value = 0;
  }
}

// ======= 上传文件分片并合并 =======
async function startUpload() {
  if (!file.value) {
    alert("请选择音频文件！");
    return;
  }

  // 重置状态
  uploading.value = true;
  recognizing.value = false;
  progress.value = 0;
  pollProgress.value = 0;
  resultText.value = "";
  summaryText.value = "";

  const totalChunks = Math.ceil(file.value.size / CHUNK_SIZE);
  const fileId = Date.now() + "_" + file.value.name;

  try {
    // --- 1. 分片上传 ---
    for (let i = 0; i < totalChunks; i++) {
      const chunk = file.value.slice(i * CHUNK_SIZE, Math.min(file.value.size, (i + 1) * CHUNK_SIZE));
      const form = new FormData();
      form.append("file", chunk);
      form.append("fileId", fileId);
      form.append("index", i);

      await api.post("/api/upload/chunk", form, {
        onUploadProgress: (e) => {
          // 计算总进度
          progress.value = Math.round(((i + e.loaded / e.total) / totalChunks) * 100);
        },
      });
    }

    // --- 2. 合并分片 ---
    const mergeRes = await api.post("/api/upload/merge", { fileId, filename: file.value.name });
    uploading.value = false;
    progress.value = 100;

    const filePath = mergeRes.data.url;
    console.log("上传合并完成，文件路径：", filePath);

    // --- 3. 自动调用百度ASR识别，启动任务 ---
    recognizing.value = true;

    // 这里的 /api/asr/baidu 调用的是 AsrController 中的 startBaiduAsr
    // 它会用 filePath 启动任务并返回 taskId
    const { data } = await api.post("/api/asr/baidu", { filePath });
    const taskId = data.taskId;

    // --- 4. 轮询识别任务 ---
    await pollRecognition(taskId);

  } catch (error) {
    uploading.value = false;
    recognizing.value = false;
    console.error("上传或任务启动失败:", error);
    alert(`处理失败: ${error.message || '请查看控制台'}`);
  }
}

// ======= 轮询识别任务 (修复了超时 bug 及失败处理) =======
async function pollRecognition(taskId) {
  const POLLING_INTERVAL = 3000; // 轮询间隔改为 3 秒 (3000ms)
  const MAX_ATTEMPTS = MAX_POLL_TIME_SECONDS / (POLLING_INTERVAL / 1000);
  let currentAttempt = 0;

  while (currentAttempt < MAX_ATTEMPTS) {
    await new Promise((r) => setTimeout(r, POLLING_INTERVAL));
    currentAttempt++;

    try {
      // 这里的 data 是后端 AsrController.getStatus 返回的 Map<String, Object>
      const { data } = await api.get("/api/asr/status", { params: { taskId } });

      // 根据等待时间更新进度条
      pollProgress.value = Math.min(Math.round((currentAttempt / MAX_ATTEMPTS) * 100), 99);

      // --- 重点判断：检查任务是否完成或失败 ---
      // 成功状态（假设您的后端将成功识别的文本放在 result 字段中，且任务状态码可能为 2 或其他）
      if (data.status === 2 || (data.status === 3 && data.raw?.task_status === 'Success')) {
        // 【关键修改：精准提取百度 ASR 文本】
        let transcript = "";
        const rawResult = data.raw?.task_result?.result; // 获取 ["AI智能BG触手。"] 数组
       /* if (data.result && typeof data.result === 'string') {
          // 优先使用后端可能已经处理好的顶层 result (如果您的后端做了这个处理)
          transcript = data.result;
        } else if (rawResult && Array.isArray(rawResult) && rawResult.length > 0) {
          // 从百度返回的原始数组中提取第一个字符串元素
          transcript = rawResult[0];
        } else {
          transcript = "（未识别出任何内容）";
        }*/
        // 优先从原始数据中提取文本，因为顶层 result 经常为空
        if (rawResult && Array.isArray(rawResult) && rawResult.length > 0) {
          // 从百度返回的原始数组中提取第一个字符串元素
          transcript = rawResult[0];
        } else if (data.result && typeof data.result === 'string' && data.result.length > 0) {
          // 只有顶层 result 存在且长度大于 0 时才使用
          transcript = data.result;
        } else {
          // 失败或未识别内容
          transcript = "（未识别出任何内容）";
        }

        pollProgress.value = 100;
        resultText.value = transcript;
        recognizing.value = false;

        // 确保识别出内容再进行 NLP 分析
        if (transcript && transcript.length > 5 && transcript !== "（未识别出任何内容）") {
          console.log("识别成功，开始文本分析...");
          const analysisRes = await api.post("/api/note/analyze", { transcript: resultText.value });
          // 假设后端 NoteController.analyze 返回 Map<String, String>，包含 "summary"
          summaryText.value = analysisRes.data.summary;
        } else {
          summaryText.value = "识别结果为空或过短，跳过分析。";
        }
        console.log("分析完成。");
        return;
      }

      // 失败状态 (根据您提供的JSON，status=3 且 task_status="Failure")
      if (data.status === 3 && data.raw?.task_status === 'Failure') {
        recognizing.value = false;
        pollProgress.value = 0; // 重置进度

        // 提取错误信息
        const errNo = data.raw?.task_result?.err_no;
        const errMsg = data.raw?.task_result?.err_msg || "未知错误";

        let displayMsg = `识别任务失败！`;
        if (errNo === 100102) {
          displayMsg += `\n错误代码 100102: 请求音频 URL 超时。请检查 Ngrok 隧道是否稳定。`;
        } else {
          displayMsg += `\n错误信息: ${errMsg} (代码: ${errNo})`;
        }

        resultText.value = displayMsg; // 将错误信息显示在结果区
        alert(displayMsg);
        return;
      }

      // status 0 或 1: 继续轮询 (无需操作，循环会自动等待)

    } catch (error) {
      recognizing.value = false;
      pollProgress.value = 0;
      console.error("轮询识别状态失败:", error);
      alert(`查询识别状态失败！${error.message}`);
      return;
    }
  }

  // 轮询超时退出循环
  recognizing.value = false;
  pollProgress.value = 0;
  alert(`识别超时！已等待超过 ${MAX_POLL_TIME_SECONDS} 秒。`);
}

// ======= 导出会议纪要 (保持不变) =======
async function exportFile(type) {
  if (!summaryText.value) {
    alert("请先完成识别和摘要生成！");
    return;
  }

  const endpoint = `/api/export/${type}`;
  try {
    const res = await api.post(
        endpoint,
        {
          title: "AI 智能笔记助手会议纪要",
          summary: summaryText.value,
          text: resultText.value,
        },
        { responseType: "blob" }
    );

    // 下载文件
    const blob = new Blob([res.data]);
    const url = window.URL.createObjectURL(blob);
    const link = document.createElement("a");
    link.href = url;
    link.download = `会议纪要_${Date.now()}.${type === "pdf" ? "pdf" : "docx"}`;
    link.click();
    window.URL.revokeObjectURL(url);
  } catch (error) {
    console.error("导出文件失败:", error);
    alert("导出文件失败，请重试。");
  }
}
</script>

<style scoped>
.upload-audio {
  padding: 20px;
  max-width: 700px;
  margin: auto;
  font-family: 'Inter', sans-serif;
}

.progress,
.recognizing {
  margin-top: 15px;
  padding: 10px;
  border: 1px solid #ccc;
  border-radius: 8px;
  background: #f0f0f0;
}

.recognizing p {
  font-weight: bold;
  color: #3f51b5;
}

.result,
.summary {
  margin-top: 25px;
  background: #ffffff;
  border-radius: 12px;
  padding: 15px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  border: 1px solid #e0e0e0;
}

.result pre,
.summary pre {
  white-space: pre-wrap;
  word-wrap: break-word;
  background-color: #f7f7f7;
  padding: 10px;
  border-radius: 6px;
  border-left: 3px solid #409eff;
}

.export-buttons {
  margin-top: 15px;
  display: flex;
  gap: 10px;
  justify-content: flex-end;
}

/* El-button styles for better aesthetics */
.el-button {
  border-radius: 6px;
  transition: all 0.2s;
}

.el-button:disabled {
  cursor: not-allowed;
  opacity: 0.6;
}
</style>